package com.ydd.common.utils;


import com.alibaba.cloud.commons.lang.StringUtils;
import com.ydd.common.exception.BusinessException;
import lombok.extern.slf4j.Slf4j;


import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneId;
import java.util.*;

@Slf4j
public class DateUtil {

    public static final String YYYY_MM_DD_HH_MM_SS = "yyyy-MM-dd HH:mm:ss";
    public static final String YYYY_MM_DD_HH_MM = "yyyy-MM-dd HH:mm";
    public static final String YYYY_MM_DD_HH = "yyyy-MM-dd HH";
    public static final String YYYY_MM_DD = "yyyy-MM-dd";
    public static final String YYYY = "yyyy";
    public static final String HH_MM_SS = "HH:mm:ss";
    public static final String DATE_OF_MONTH = "01,02,03,04,05,06,07,08,09,10,11,12";
    public static final String DATE_OF_WEEK = "w1,w2,w3,w4,w5,w6,w7";
    public static final String DATE_OF_MAX_DATE = "2099-12-31 00:00:00";
    public static final String DATE_FORMAT_FOR_ORACLE = "yyyy-mm-dd hh24:mi:ss";

    /**
     * 按照指定的格式将字符串转换为日期类型
     */
    public static Date str2Date(String dateStr, String format) throws ParseException {
        Date dateRs = new Date();
        if (dateStr != null && format != null) {
            SimpleDateFormat sdf = new SimpleDateFormat(format);
            dateRs = sdf.parse(dateStr);
        }
        return dateRs;
    }

    /**
     * 按照指定的格式将日期类型转换为字符串
     *
     * @param date 时间
     * @param format 格式
     */
    public static String date2Str(Date date, String format) {
        String str = null;
        if (date != null && format != null) {
            SimpleDateFormat sdf = new SimpleDateFormat(format);
            str = sdf.format(date);
        }
        return str;
    }

    public static Date convert(String source, String format) {
        try {
            SimpleDateFormat simpleDateFormat = new SimpleDateFormat(format, Locale.CHINA);
            simpleDateFormat.parse(source);
            return simpleDateFormat.parse(source);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }
        return null;
    }

    public static String millisecond(Long millisecond, SimpleDateFormat sdf) {
        Date date = new Date(millisecond);
        return sdf.format(date);
    }

    /**
     * 根据时间字符串返回Date对象
     *
     * @param dateStr ,可以接受3种格式分别是:yyyy-MM-dd,yyyy-MM-dd HH:mm,yyyy-MM-dd HH:mm:ss
     */
    public static Date str2Date(String dateStr) {
        SimpleDateFormat formatter;
        if (dateStr.length() == 10)
            formatter = new SimpleDateFormat(DateUtil.YYYY_MM_DD);
        else if (dateStr.length() == 16)
            formatter = new SimpleDateFormat(DateUtil.YYYY_MM_DD_HH_MM);
        else if (dateStr.length() == 19)
            formatter = new SimpleDateFormat(DateUtil.YYYY_MM_DD_HH_MM_SS);
        else {
            return null;
        }
        try {
            return formatter.parse(dateStr);
        } catch (ParseException e) {
            log.error(e.getMessage(), e);
        }
        return null;
    }


    /**
     * 默认日期转换类型
     *
     * @param dateStr 时间字符串
     */
    public static Date defStr2Date(String dateStr) throws ParseException {
        return str2Date(dateStr, DateUtil.YYYY_MM_DD_HH_MM_SS);
    }

    /**
     * 默认字符串转换类型
     *
     * @param date 日期
     */
    public static String defDate2Str(Date date) {
        return date2Str(date, DateUtil.YYYY_MM_DD_HH_MM_SS);
    }

    /**
     * 默认日期转换类型
     *
     * @param dateStr 时间字符串
     */
    public static Date toDate(String dateStr) {
        try {
            return str2Date(dateStr, DateUtil.YYYY_MM_DD);
        } catch (ParseException e) {
            log.error(e.getMessage(), e);
            throw new BusinessException("时间转换异常：" + e.getMessage());
        }
    }

    public static Date getCurrentDate() {
        String nowStr = DateUtil.date2Str(new Date(), DateUtil.YYYY_MM_DD);
        return DateUtil.toDate(nowStr);
    }

    /**
     * 根据给定的时间计算周末(星期六)日期
     *
     * @param curDate 当前日期
     */
    public static Date getWeekend(Date curDate) {
        Date date;
        Calendar cal = Calendar.getInstance();
        cal.setTime(curDate);
        int curDay = cal.get(Calendar.DAY_OF_WEEK);
        if (curDay != Calendar.SATURDAY) {
            cal.add(Calendar.DAY_OF_MONTH, Calendar.SATURDAY - curDay);
            date = cal.getTime();
        } else {
            date = curDate;
        }
        return date;
    }

    /**
     * 计算两个时间差，返回长整型
     *
     * @param maxDate 最大时间
     * @param minDate 最小时间
     */
    public static long dateDiff(Date maxDate, Date minDate) {

        return maxDate.getTime() - minDate.getTime();
    }

    /**
     * 传入一个日期 获得这个日期所在一周内的所有天数的一个List
     *
     * @param mDate 日期
     */
    public static List<Date> dateToWeek(Date mDate) {
        int b = mDate.getDay();
        Date fDate;
        List<Date> list = new ArrayList<>();
        long fTime = mDate.getTime() - b * 24 * 3600000;
        for (int a = 0; a < 7; a++) {
            fDate = new Date();
            fDate.setTime(fTime + (a * 24 * 3600000));
            list.add(a, fDate);
        }
        return list;
    }

    /**
     * 传入一个日期 获取这个日期所在的周几
     */
    public static int dateToWeekDay(Date date) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        int return_value = cal.get(Calendar.DAY_OF_WEEK);
        return return_value == 0 ? 7 : return_value;
    }

    /**
     * 传入一个日期 获取这个日期所在的年，月，日，周几
     */
    public static Map<String, String> forMartDate(Date date) {
        Map<String, String> map = new HashMap<>();
        map.put("year", new SimpleDateFormat("yyyy").format(date));
        map.put("month", new SimpleDateFormat("MM").format(date));
        map.put("day", new SimpleDateFormat("dd").format(date));
        map.put("week", "w" + dateToWeekDay(date));
        return map;
    }

    /**
     * 传入一个日期，获取一周的天
     *
     * @param date 日期
     */
    public static List<String> getWeekDay(Date date) {
        List<Date> list = dateToWeek(date);
        List<String> rtList = new ArrayList<>();
        for (Date d : list) {
            rtList.add(forMartDate(d).get("day"));
        }
        return rtList;
    }

    /**
     * 返回周天
     */
    public static List<String> getWeekDay() {
        List<String> rtList = new ArrayList<>();
        String str;
        for (int i = 1; i < 8; i++) {
            str = "w" + i;
            rtList.add(str);
        }
        return rtList;
    }

    /**
     * 获得两个日期之间的月份
     *
     * @param startDate
     * @param endDate
     */
    public static List<String> getMonth(Date startDate, Date endDate) {
        Calendar cal_s = Calendar.getInstance();
        Calendar cal_e = Calendar.getInstance();
        cal_s.setTime(startDate);
        cal_e.setTime(endDate);
        List<String> returnList = new ArrayList<>();
        while (cal_s.get(Calendar.MONTH) <= cal_e.get(Calendar.MONTH)) {
            int month = cal_s.get(Calendar.MONTH) + 1;
            String month_s = month < 10 ? "0" + month : String.valueOf(month);
            returnList.add(month_s);
            cal_s.add(Calendar.MONTH, +1);
        }
        return returnList;
    }

    /**
     * 获得两个日期之间的天
     *
     * @param startDate
     * @param endDate
     */
    public static List<String> getDays(Date startDate, Date endDate) {
        Calendar cal_s = Calendar.getInstance();
        Calendar cal_e = Calendar.getInstance();
        cal_s.setTime(startDate);
        cal_e.setTime(endDate);
        List<String> returnList = new ArrayList<>();
        int day;
        String day_s;
        while (cal_s.get(Calendar.DAY_OF_MONTH) < cal_e.get(Calendar.DAY_OF_MONTH)) {
            day = cal_s.get(Calendar.DAY_OF_MONTH);
            day_s = day < 10 ? "0" + day : String.valueOf(day);
            returnList.add(day_s);
            cal_s.add(Calendar.DAY_OF_MONTH, +1);
        }
        day = cal_s.get(Calendar.DAY_OF_MONTH);
        day_s = day < 10 ? "0" + day : String.valueOf(day);
        returnList.add(day_s);
        return returnList;
    }

    /**
     * 获取两个时间之间的天数
     *
     * @param date1
     * @param date2
     */
    public static int getMonthSpace(String date1, String date2) throws ParseException {

        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");

        Calendar c1 = Calendar.getInstance();
        Calendar c2 = Calendar.getInstance();

        c1.setTime(sdf.parse(date1));
        c2.setTime(sdf.parse(date2));

        int result = c2.get(Calendar.DATE) - c1.get(Calendar.DATE);

        return result == 0 ? 1 : Math.abs(result);

    }


    /**
     * 改变日期的值
     *
     * @param date
     * @param changeMode  : Calendar.MONTH,Calendar.DAY,Calendar.DAY_OF_MONTH,Calendar.DAY_OF_WEEK等
     * @param changeValue
     */
    public static Date getChangeDate(Date date, int changeMode, int changeValue) {
        Calendar ca = Calendar.getInstance();
        ca.setTime(date);
        ca.add(changeMode, changeValue);
        return ca.getTime();
    }

    /**
     * 获得上分钟的日期(如2012-02-03 12:30:00~2012-02-03 12:30:59)
     */
    public static Date[] getLastMinute() {
        Calendar ca = Calendar.getInstance();
        ca.add(Calendar.MINUTE, -1);
        ca.set(Calendar.SECOND, 59);
        Date end = ca.getTime();
        ca.set(Calendar.SECOND, 0);
        Date start = ca.getTime();
        return new Date[]{start, end};
    }

    /**
     * 获得下周的日期(星期日至星期六)
     */
    public static Date[] getLastDay() {
        Calendar ca = Calendar.getInstance();
        ca.add(Calendar.DATE, -1);
        ca.set(Calendar.HOUR_OF_DAY, 0);
        ca.set(Calendar.MINUTE, 0);
        ca.set(Calendar.SECOND, 0);
        Date start = ca.getTime();
        ca.set(Calendar.HOUR_OF_DAY, 23);
        ca.set(Calendar.MINUTE, 59);
        ca.set(Calendar.SECOND, 59);
        Date end = ca.getTime();
        return new Date[]{start, ca.getTime()};
    }

    /**
     * 获得上个月日期(如2012-01-03 12:30:00~2012-02-03 12:30:59)
     */
    public static Date[] getLastMonth() {
        Calendar ca = Calendar.getInstance();
        ca.add(Calendar.MONTH, -1);
        ca.set(Calendar.DAY_OF_MONTH, 0);
        ca.set(Calendar.HOUR_OF_DAY, 0);
        ca.set(Calendar.MINUTE, 0);
        ca.set(Calendar.SECOND, 0);
        Date start = ca.getTime();
        ca.set(Calendar.DAY_OF_MONTH, ca.getMaximum(Calendar.DAY_OF_MONTH));
        ca.set(Calendar.HOUR_OF_DAY, 23);
        ca.set(Calendar.MINUTE, 59);
        ca.set(Calendar.SECOND, 59);
        Date end = ca.getTime();
        return new Date[]{start, end};
    }

    /**
     * 获得上一年的日期(如2012-01-03 12:30:00~2012-02-03 12:30:59)
     */
    public static Date[] getLastYear() {
        Calendar ca = Calendar.getInstance();
        ca.add(Calendar.YEAR, -1);
        ca.set(Calendar.MONTH, 0);
        ca.set(Calendar.DAY_OF_MONTH, 0);
        ca.set(Calendar.HOUR_OF_DAY, 0);
        ca.set(Calendar.MINUTE, 0);
        ca.set(Calendar.SECOND, 0);
        Date start = ca.getTime();
        ca.set(Calendar.MONTH, ca.getMaximum(Calendar.MONTH));
        ca.set(Calendar.DAY_OF_MONTH, ca.getMaximum(Calendar.DAY_OF_MONTH));
        ca.set(Calendar.HOUR_OF_DAY, 23);
        ca.set(Calendar.MINUTE, 59);
        ca.set(Calendar.SECOND, 59);

        Date end = ca.getTime();
        return new Date[]{start, end};
    }

    public static int getYear() {
        Calendar calendar = Calendar.getInstance();
        return calendar.get(Calendar.YEAR);
    }


    /**
     * 获得昨天的日期(如2012-01-03 12:30:00~2012-02-03 12:30:59)
     */
    public static Date[] getNextWeek() {
        Calendar ca = Calendar.getInstance();
        ca.add(Calendar.WEEK_OF_MONTH, 1);
        ca.set(Calendar.DAY_OF_WEEK, 1);
        Date start = ca.getTime();
        ca.set(Calendar.DAY_OF_WEEK, 7);
        Date end = ca.getTime();
        return new Date[]{start, end};
    }

    /**
     * 获得第一个跨星期的日期，如果没有跨星期返回null
     *
     * @param date    日期
     * @param seconds
     */
    public static Date getCrossWeekDate(Date date, long seconds) {
        Calendar ca = Calendar.getInstance();
        ca.add(Calendar.DATE, 1 - ca.get(Calendar.DAY_OF_WEEK));
        ca.set(Calendar.HOUR, 0);
        ca.set(Calendar.MINUTE, 0);
        ca.set(Calendar.SECOND, 0);
        long dif = dateDiff(date, ca.getTime());
        if (dif < seconds) {
            return ca.getTime();
        } else {
            return null;
        }
    }

    /**
     * 是否小于年份
     *
     * @param src    源年分字符串
     * @param target 目标年份字符串
     * @return
     */
    public static boolean isLessLhan(String src, String target) {
        if (src == null || target == null) {
            return false;
        }
        int res = src.compareTo(target);
        return res < 0;
    }

    /**
     * 获取2天前的日期（少20分钟）fyh
     *
     * @param
     * @return
     */
    public static Date getNearlyOneDay(int num) {
        Calendar ca = Calendar.getInstance();
        ca.add(Calendar.MINUTE, 0);
        ca.add(Calendar.DAY_OF_YEAR, num);
        ca.set(Calendar.SECOND, 59);

        return ca.getTime();
    }

    public static Date getAddMonth(int m) {
        Calendar ca = Calendar.getInstance();
        ca.add(Calendar.MONTH, m);
        ca.set(Calendar.DAY_OF_MONTH, 0);
        ca.set(Calendar.HOUR_OF_DAY, 0);
        ca.set(Calendar.MINUTE, 0);
        ca.set(Calendar.SECOND, 0);
        return ca.getTime();
    }

    public static Date getHour() {
        Calendar ca = Calendar.getInstance();
        ca.set(Calendar.MINUTE, ca.get(Calendar.MINUTE) - 30);
        return ca.getTime();
    }

    public static Date getOneHour() {
        Calendar ca = Calendar.getInstance();
        ca.set(Calendar.MINUTE, ca.get(Calendar.MINUTE) - 60);
        return ca.getTime();
    }

    public static Date getAddDay(int d) {
        Calendar ca = Calendar.getInstance();
        ca.add(Calendar.DATE, d);
        return ca.getTime();
    }

    /**
     * 获取指定日期的后几天
     *
     * @param specifiedDay
     * @param num
     */
    public static String getSpecifiedDayAfter(String specifiedDay, int num) {
        Calendar c = Calendar.getInstance();
        Date date;
        try {
            date = new SimpleDateFormat("yy-MM-dd").parse(specifiedDay);
        } catch (ParseException e) {
            log.error(e.getMessage(), e);
            throw new BusinessException(e.getMessage());
        }
        c.setTime(date);
        int day = c.get(Calendar.DATE);
        c.set(Calendar.DATE, day + num);

        return new SimpleDateFormat("yyyy-MM-dd").format(c.getTime());
    }

    /**
     * 获取指定日期的后几天
     *
     * @param specifiedDay 日期
     * @param num          天数
     */
    public static String getSpecifiedDayAfterOther(String specifiedDay, int num) {
        Calendar c = Calendar.getInstance();
        Date date;
        try {
            date = new SimpleDateFormat("yyyyMMdd").parse(specifiedDay);
        } catch (ParseException e) {
            log.error(e.getMessage(), e);
            throw new BusinessException(e.getMessage());
        }
        c.setTime(date);
        int day = c.get(Calendar.DATE);
        c.set(Calendar.DATE, day + num);

        return new SimpleDateFormat("yyyyMMdd").format(c.getTime());
    }

    /**
     * 判断现在是否在时间段内（小时:分钟）
     *
     * @param start 开始时间
     * @param end   结束时间
     */
    public static boolean nowIsInRange(String start, String end) {
        if (StringUtils.isBlank(start) || StringUtils.isBlank(end)) {
            return false;
        }
        SimpleDateFormat sdf = new SimpleDateFormat("HH.mm");
        String curTime = sdf.format(new Date());
        double now = Double.parseDouble(curTime);
        double startNum = Double.parseDouble(start.replace(":", "."));
        double endNum = Double.parseDouble(end.replace(":", "."));
        return startNum < now && endNum > now;
    }

    //判断选择的日期是否是本周
    public static boolean isThisWeek(long time) {
        Calendar calendar = Calendar.getInstance();
        int currentWeek = calendar.get(Calendar.WEEK_OF_YEAR);
        calendar.setTime(new Date(time));
        int paramWeek = calendar.get(Calendar.WEEK_OF_YEAR);
        return paramWeek == currentWeek;
    }

    //判断选择的日期是否是今天  
    public static boolean isToday(long time) {
        return isThisTime(time, "yyyy-MM-dd");
    }

    //判断选择的日期是否是本月  
    public static boolean isThisMonth(long time) {
        return isThisTime(time, "yyyy-MM");
    }

    private static boolean isThisTime(long time, String pattern) {
        Date date = new Date(time);
        SimpleDateFormat sdf = new SimpleDateFormat(pattern);
        String param = sdf.format(date);//参数时间
        String now = sdf.format(new Date());//当前时间
        return param.equals(now);
    }

    public static int getMonthDiff(Date startDate, Date endDate) {
        Calendar c1 = Calendar.getInstance();
        c1.setTime(startDate);

        Calendar c2 = Calendar.getInstance();
        c2.setTime(endDate);

        int year1 = c1.get(Calendar.YEAR);

        int year2 = c2.get(Calendar.YEAR);

        int month1 = c1.get(Calendar.MONTH);

        int month2 = c2.get(Calendar.MONTH);

        int day1 = c1.get(Calendar.DAY_OF_MONTH);

        int day2 = c2.get(Calendar.DAY_OF_MONTH);

        // 获取年的差值

        int yearInterval = year1 - year2;

        // 如果 d1的 月-日 小于 d2的 月-日 那么 yearInterval-- 这样就得到了相差的年数

        if (month1 < month2 || month1 == month2 && day1 < day2) {
            yearInterval--;
        }

        // 获取月数差值
        int monthInterval = (month1 + 12) - month2;

        if (day1 < day2) {
            monthInterval--;
        }

        monthInterval %= 12;

        return Math.abs(yearInterval * 12 + monthInterval);
    }

    /**
     * @Description: 获取日期开始时间
     * @author wumin
     * @date 2021-07-06 14:18
     * @param date 日期
     * @return java.util.Date
     */
    public static Date getDayStartTime(Date date) {
        LocalDate localDate = date.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
        LocalDateTime localDateTime = LocalDateTime.of(localDate, LocalTime.MIN);
        return Date.from(localDateTime.atZone(ZoneId.systemDefault()).toInstant());
    }

    /**
     * @Description: 获取今天开始时间
     * @author wumin
     * @date 2021-07-06 14:18
     * @return java.util.Date
     */
    public static Date getTodayStartTime() {
        LocalDateTime localDateTime = LocalDateTime.of(LocalDate.now(), LocalTime.MIN);
        return Date.from(localDateTime.atZone(ZoneId.systemDefault()).toInstant());
    }

    /**
     * @Description: 获取日期结束时间
     * @author wumin
     * @date 2021-07-06 14:19
     * @param date 日期
     * @return java.util.Date
     */
    public static Date getDayEndTime(Date date) {
        LocalDate localDate = date.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
        LocalDateTime localDateTime = LocalDateTime.of(localDate, LocalTime.MAX);
        return Date.from(localDateTime.atZone(ZoneId.systemDefault()).toInstant());
    }

    /**
     * @Description: 获取今天结束时间
     * @author wumin
     * @date 2021-07-06 14:19
     * @return java.util.Date
     */
    public static Date getTodayEndTime() {
        LocalDateTime localDateTime = LocalDateTime.of(LocalDate.now(), LocalTime.MIN);
        return Date.from(localDateTime.atZone(ZoneId.systemDefault()).toInstant());
    }

    public static String offsetYear(Date expireDate, int i) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(expireDate);
        calendar.add(Calendar.YEAR, i);
        return new SimpleDateFormat("yyyy-MM-dd").format(calendar.getTime());
    }

    public static void main(String[] args) {
        String startStr = "2023.1.01 00:00:00";
        String endStr = "2023.1.21 23:59:59";
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss");
        try {
            Date start = sdf.parse(startStr);
            Date end = sdf.parse(endStr);
            System.out.println(getMonthDiff(start,end));
        } catch (ParseException e) {
            throw new RuntimeException(e);
        }

    }
}
